/*
 * Copyright (c) 2001, Maynard Demmon
 * Copyright (c) 2001, Organic
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice, this 
 *    list of conditions and the following disclaimer.
 * 
 *  - Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution. 
 *
 *  - Neither the name of Organic nor the names of its contributors may 
 *    be used to endorse or promote products derived from this software without 
 *    specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 */

package com.organic.maynard.util.string;

import java.io.File;
import java.util.ArrayList;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.organic.maynard.outliner.util.preferences.Preferences;

public class StringTools {
	/** Pattern to match a string with a three character extension that captures the entire string except the extension */
	private static Pattern TRIMMED_FILENAME = Pattern.compile("(.+)\\....$");

	
	// Constructor
	public StringTools() {}
	
	
	// Class Methods
	public static String replace(String in, String match, String replacement) {
		// check for null refs
		if (in == null || match == null || replacement == null) {
			return in;
		}
		
		StringBuffer out = new StringBuffer();
		
		int matchLength = match.length();
		int inLength = in.length();
		
		for (int i = 0; i < inLength; i++) {
			int upperSearhLimit = i + matchLength;
			if ((upperSearhLimit <= inLength) && (in.substring(i,upperSearhLimit).equals(match))) {
				out.append(replacement);
				i = upperSearhLimit - 1;
			} else {
				out.append(in.charAt(i));
			}
		}
		return out.toString();
	}
	
	public static int startsWith(String text, String match) {
		Pattern p = Pattern.compile(String.format("^(%s+)", match));
		Matcher m = p.matcher(text);
		if (m.matches()) {
			return contains(m.group(0), match);
		} else {
			return 0;
		}
	}
	
	public static int contains(String text, String match) {
		Pattern p = Pattern.compile(match);
		Matcher m = p.matcher(text);
		int counter = 0;
		while(m.find()) { counter++; }
		return counter;
	}
	
	public static String trimExtension(String text, String separator) {
		int index = text.lastIndexOf(separator);
		if (index == -1) {
			return text;
		} else {
			return text.substring(0, index);
		}
	}
	
	public static String escape(String text, char escapeChar,  char[] reserved) {
		StringBuffer buf = new StringBuffer();
		
		for (int i = 0; i < text.length(); i++) {
			char c = text.charAt(i);
			
			// Is the char reserved
			boolean isReserved = false;
			if (reserved != null) {
				for (int j = 0; j < reserved.length; j++) {
					if (c == reserved[j]) {
						isReserved = true;
						break;
					}
				}
			}
			
			// Deal with the type of char
			if (c == escapeChar) {
				buf.append(escapeChar).append(escapeChar);
			} else if (isReserved) {
				buf.append(escapeChar).append(c);
			} else {
				buf.append(c);
			}
		}
		
		return buf.toString();
	}
	
	public static Vector<String> split(String text, char escapeChar, char[] delimiters) {
		Vector<String> parts = new Vector<String>();
		
		boolean isEscaped = false;
		
		StringBuffer part = new StringBuffer();
		
		for (int i = 0; i < text.length(); i++) {
			char c = text.charAt(i);
			
			// Is the char a delimiter
			boolean isDelimiter = false;
			for (int j = 0; j < delimiters.length; j++) {
				if (c == delimiters[j]) {
					isDelimiter = true;
					break;
				}
			}
			
			// Deal with the type of char
			if (c == escapeChar) {
				if (isEscaped) {
					part.append(c);
					isEscaped = false;
				} else {
					isEscaped = true;
				}			
			} else if (isDelimiter) {
				if (isEscaped) {
					part.append(c);
					isEscaped = false;
				} else {
					parts.add(part.toString());
					part.setLength(0);
				}
			} else {
				if (isEscaped) {
					part.append(c);
					isEscaped = false;
				} else {
					part.append(c);
				}
			}
		}
		
		// Append the last section
		parts.add(part.toString());
		
		return parts;
	}
	
	public static void split(ArrayList<String> parts, String text, char escapeChar, char[] delimiters) {
		boolean isEscaped = false;
		boolean isDelimiter = false;
		StringBuffer part = new StringBuffer();
		
		for (int i = 0, limit = text.length(); i < limit; i++) {
			char c = text.charAt(i);
			
			// Is the char a delimiter
			for (int j = 0; j < delimiters.length; j++) {
				if (c == delimiters[j]) {
					isDelimiter = true;
					break;
				}
			}
			
			// Deal with the type of char
			if (isDelimiter) {
				if (isEscaped) {
					part.append(c);
					isEscaped = false;
				} else {
					parts.add(part.toString());
					part.setLength(0);
				}
				isDelimiter = false;
			} else if (c == escapeChar) {
				if (isEscaped) {
					part.append(c);
					isEscaped = false;
				} else {
					isEscaped = true;
				}
			} else {
				if (isEscaped) {
					isEscaped = false;
				}
				part.append(c);
			}
		}
		
		// Append the last section
		parts.add(part.toString());
	}
	
	public static String getExtension(String filename) {
		int index = filename.lastIndexOf(Preferences.EXTENSION_SEPARATOR);
		if (index == -1) {
			return null;
		} else {
			return filename.substring(index + 1, filename.length());
		}
	}


	// trim off last four characters if there's a dot three chars before the end
	public static String trimFileExtension(String fileNameString) {
		
		Matcher m = TRIMMED_FILENAME.matcher(fileNameString);
		
		if (m.matches()) {
			return m.group(1);
		} else {
			return fileNameString;
		}
		
	} // end method trimOffAnyFileExtension


	// grab a filename from a pathname
	public static String getFileNameFromPathName(String pathNameString) {
		
		File file = new File (pathNameString) ;
		if (file == null) {
			return null ;
		} else {
			return file.getName() ;
		} // end else
		
	} // end method trimOffAnyFileExtension


	// return a truncated pathname
	public static String getTruncatedPathName(String pathNameString, String truncationString) {
		
		// we keep info thru the first directory
		// then separator..separator
		// then filename
		
		// if just two separators in pathname, we do nothing
		// c:\foo.txt
		// one separator, do nothing
		
		// c:\moo\foo.txt
		// two separators, do nothing
		
		// c:\moo\boo\foo.txt
		// three separators
		// replace info tween separators 2 and 3 with ..
		// c:\moo\..\foo.txt
		
		// c:\moo\boo\goo\foo.txt
		// four separators
		// replace
		
		// so: our scheme:
		// scan for separators, from left
		// note positions of 2nd and, if more than 2, last
		
		// then: build a string out of substring thru 2nd sep
		// plus our trunc string
		// plus substring from last sep thru til end
		
		// local vars
		int secondSeparator = -1 ;
		int lastSeparator = -1 ;
		int length = pathNameString.length() ;
		
		// we're scanning the full string
		for (int scanner = 0, separatorCount = 0; scanner < length; scanner ++) {
			// if we find a separator char ...
			if (pathNameString.charAt(scanner) == File.separatorChar) {
				// note the find
				separatorCount ++ ;
				// if this is the second separator ..
				if (separatorCount == 2) {
					secondSeparator = scanner ;
				// else it's provisionally the last separator
				} else {
					lastSeparator = scanner ;
				} // end if-else
			} // end if
		} // end for
		
		// if we have 2 or fewer separators, just return the pathname
		if ( (secondSeparator == -1) ||  (lastSeparator < secondSeparator) ) {
			return pathNameString ;
		} // end if
		
		// okay, we have more than 2 separators
		// [srk] var here just temp for testing ... return directly once cooked
		String resultString = (pathNameString.substring(0, secondSeparator + 1)
			+ truncationString
			+ pathNameString.substring(lastSeparator, length)) ;
		
		return resultString ;
		
	} // end method getTruncatedPathName

}